{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp models.explainability"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Model explainability\n",
    "> Functionality to help with both global and local explainability."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from tsai.utils import *\n",
    "from tsai.models.layers import *\n",
    "from tsai.models.utils import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([64, 6])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from tsai.data.all import *\n",
    "from tsai.models.XCM import *\n",
    "\n",
    "dsid = 'NATOPS'\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False)\n",
    "tfms = [None, Categorize()]\n",
    "dls = get_ts_dls(X, y, splits=splits, tfms=tfms)\n",
    "model =  XCM(dls.vars, dls.c, dls.len)\n",
    "learn = Learner(dls, model, metrics=accuracy)\n",
    "xb, yb = dls.one_batch()\n",
    "x = xb[0]\n",
    "model.eval().to(xb.device)(xb).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_acts_and_grads(model, modules, x, y=None, detach=True, cpu=False):\n",
    "    r\"\"\"Returns activations and gradients for given modules in a model and a single input or a batch. \n",
    "    Gradients require y value(s). If they rae not provided, it will use the predicttions. \"\"\"\n",
    "    if not is_listy(modules): modules = [modules]\n",
    "    x = x[None, None] if x.ndim == 1 else x[None] if x.ndim == 2 else x\n",
    "    with hook_outputs(modules, detach=detach, cpu=cpu) as h_act:\n",
    "        with hook_outputs(modules, grad=True, detach=detach, cpu=cpu) as h_grad:\n",
    "            preds = model.eval()(x)\n",
    "            if y is None: preds.max(dim=-1).values.mean().backward()\n",
    "            else: \n",
    "                if preds.shape[0] == 1: preds[0, y].backward()\n",
    "                else: \n",
    "                    if y.ndim == 1: y = y.reshape(-1, 1)\n",
    "                    torch_slice_by_dim(preds, y).mean().backward()\n",
    "    if len(modules) == 1: return h_act.stored[0].data, h_grad.stored[0][0].data\n",
    "    else: return [h.data for h in h_act.stored], [h[0].data for h in h_grad.stored]\n",
    "\n",
    "\n",
    "def get_attribution_map(model, modules, x, y=None, detach=True, cpu=False, apply_relu=True):\n",
    "    def _get_attribution_map(A_k, w_ck):\n",
    "        dim = (0, 2, 3) if A_k.ndim == 4 else (0, 2)\n",
    "        w_ck = w_ck.mean(dim, keepdim=True)\n",
    "        L_c = (w_ck * A_k).sum(1)\n",
    "        if apply_relu: L_c = nn.ReLU()(L_c)\n",
    "        if L_c.ndim == 3:  return L_c.squeeze(0) if L_c.shape[0] == 1 else L_c\n",
    "        else: return L_c.repeat(x.shape[1], 1) if L_c.shape[0] == 1 else L_c.unsqueeze(1).repeat(1, x.shape[1], 1)\n",
    "    if x.ndim == 1: x = x[None, None]\n",
    "    elif x.ndim == 2: x = x[None]\n",
    "    A_k, w_ck = get_acts_and_grads(model, modules, x, y, detach=detach, cpu=cpu)\n",
    "    if is_listy(A_k): return [_get_attribution_map(A_k[i], w_ck[i]) for i in range(len(A_k))]\n",
    "    else: return _get_attribution_map(A_k, w_ck)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/nacho/opt/anaconda3/envs/py36/lib/python3.6/site-packages/torch/nn/modules/module.py:974: UserWarning: Using a non-full backward hook when the forward contains multiple autograd Nodes is deprecated and will be removed in future versions. This hook will be missing some grad_input. Please use register_full_backward_hook to get the documented behavior.\n",
      "  warnings.warn(\"Using a non-full backward hook when the forward contains multiple autograd Nodes \"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 128, 24, 51]), torch.Size([1, 128, 24, 51]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, model.conv2dblock, x)\n",
    "acts.shape, grads.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([64, 128, 24, 51]), torch.Size([64, 128, 24, 51]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, model.conv2dblock, xb)\n",
    "acts.shape, grads.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([64, 128, 24, 51]), torch.Size([64, 128, 24, 51]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, model.conv2dblock, xb, yb)\n",
    "acts.shape, grads.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([64, 128, 51]), torch.Size([64, 128, 51]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, model.conv1dblock, xb)\n",
    "acts.shape, grads.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([torch.Size([64, 128, 24, 51]), torch.Size([64, 128, 51])],\n",
       " [torch.Size([64, 128, 24, 51]), torch.Size([64, 128, 51])])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, [model.conv2dblock, model.conv1dblock], xb, yb)\n",
    "[act.shape for act in acts], [grad.shape for grad in grads]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([64, 24, 51])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, model.conv2dblock, xb, yb)\n",
    "att_maps.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([64, 24, 51])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, model.conv1dblock, xb)\n",
    "att_maps.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[torch.Size([64, 24, 51]), torch.Size([64, 24, 51])]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, [model.conv2dblock, model.conv1dblock], xb)\n",
    "[am.shape for am in att_maps]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 2 torch.Size([1, 128, 24, 51]) torch.Size([1, 128, 24, 51])\n",
      "torch.Size([1, 128, 24, 51]) torch.Size([1, 128, 24, 51])\n"
     ]
    }
   ],
   "source": [
    "acts, grads = get_acts_and_grads(model, [model.conv2dblock, model.conv1dblock], xb[0], yb[0], detach=True, cpu=False)\n",
    "print(len(acts), len(grads), acts[0].shape, grads[0].shape)\n",
    "acts, grads = get_acts_and_grads(model, model.conv2dblock, xb[0], y=None, detach=True, cpu=False)\n",
    "print(acts.shape, grads.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([24, 51])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, model.conv2dblock, x)\n",
    "att_maps.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([24, 51])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, model.conv1dblock, x)\n",
    "att_maps.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[torch.Size([24, 51]), torch.Size([24, 51])]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, [model.conv2dblock, model.conv1dblock], x)\n",
    "[am.shape for am in att_maps]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x720 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "att_maps = get_attribution_map(model, [model.conv2dblock, model.conv1dblock], x)\n",
    "att_maps[0] = (att_maps[0] - att_maps[0].min()) / (att_maps[0].max() - att_maps[0].min())\n",
    "att_maps[1] = (att_maps[1] - att_maps[1].min()) / (att_maps[1].max() - att_maps[1].min())\n",
    "\n",
    "fig = plt.figure(figsize=(10, 10))\n",
    "ax = plt.axes()\n",
    "plt.title('Observed variables')\n",
    "im = ax.imshow(att_maps[0].cpu().numpy(), cmap='inferno')\n",
    "cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])\n",
    "plt.colorbar(im, cax=cax)\n",
    "plt.show()\n",
    "\n",
    "fig = plt.figure(figsize=(10, 10))\n",
    "ax = plt.axes()\n",
    "plt.title('Time')\n",
    "im = ax.imshow(att_maps[1].cpu().numpy(), cmap='inferno')\n",
    "cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])\n",
    "plt.colorbar(im, cax=cax)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# '''\n",
    "# Color parts of a line based on its properties, e.g., slope.\n",
    "# '''\n",
    "\n",
    "# import numpy as np\n",
    "# import matplotlib.pyplot as plt\n",
    "# from matplotlib.collections import LineCollection\n",
    "# from matplotlib.colors import ListedColormap, BoundaryNorm\n",
    "\n",
    "# x = np.linspace(0, 3 * np.pi, 500)\n",
    "# y = np.sin(x)\n",
    "# z = np.cos(0.5 * (x[:-1] + x[1:]))  # first derivative\n",
    "\n",
    "# # Create a colormap for red, green and blue and a norm to color\n",
    "# # f' < -0.5 red, f' > 0.5 blue, and the rest green\n",
    "# cmap = ListedColormap(['r', 'g', 'b'])\n",
    "# norm = BoundaryNorm([-1, -0.5, 0.5, 1], cmap.N)\n",
    "\n",
    "# # Create a set of line segments so that we can color them individually\n",
    "# # This creates the points as a N x 1 x 2 array so that we can stack points\n",
    "# # together easily to get the segments. The segments array for line collection\n",
    "# # needs to be numlines x points per line x 2 (x and y)\n",
    "# points = np.array([x, y]).T.reshape(-1, 1, 2)\n",
    "# segments = np.concatenate([points[:-1], points[1:]], axis=1)\n",
    "\n",
    "# # Create the line collection object, setting the colormapping parameters.\n",
    "# # Have to set the actual values used for colormapping separately.\n",
    "# lc = LineCollection(segments, cmap=cmap, norm=norm)\n",
    "# lc.set_array(z)\n",
    "# lc.set_linewidth(3)\n",
    "\n",
    "# fig1 = plt.figure()\n",
    "# plt.gca().add_collection(lc)\n",
    "# plt.xlim(x.min(), x.max())\n",
    "# plt.ylim(-1.1, 1.1)\n",
    "\n",
    "# # Now do a second plot coloring the curve using a continuous colormap\n",
    "# t = np.linspace(0, 10, 200)\n",
    "# x = np.cos(np.pi * t)\n",
    "# y = np.sin(t)\n",
    "# points = np.array([x, y]).T.reshape(-1, 1, 2)\n",
    "# segments = np.concatenate([points[:-1], points[1:]], axis=1)\n",
    "\n",
    "# lc = LineCollection(segments, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0, 10))\n",
    "# lc.set_array(t)\n",
    "# lc.set_linewidth(3)\n",
    "\n",
    "# fig2 = plt.figure()\n",
    "# plt.gca().add_collection(lc)\n",
    "# plt.xlim(-1, 1)\n",
    "# plt.ylim(-1, 1)\n",
    "# plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from tsai.imports import create_scripts\n",
    "from tsai.export import get_nb_name\n",
    "nb_name = get_nb_name()\n",
    "create_scripts(nb_name)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
